import { IVec2 } from "../../util/Defined";
import { MathUtil } from "../../util/MathUtil";
import { TypeUtil } from "../../util/TypeUtil";

/**
 * 二维对象
 */
export class Vec2 implements IVec2 {

    /** 零点 */
    static readonly ZERO = TypeUtil.readonlyType(new Vec2(0, 0));
    /** 右方向 */
    static readonly RIGHT = TypeUtil.readonlyType(new Vec2(1, 0));
    /** 左方向 */
    static readonly LEFT = TypeUtil.readonlyType(new Vec2(-1, 0));
    /** 上方向 */
    static readonly UP = TypeUtil.readonlyType(new Vec2(0, 1));
    /** 下方向 */
    static readonly DOWN = TypeUtil.readonlyType(new Vec2(0, -1));
    /** (1,1) */
    static readonly ONE = TypeUtil.readonlyType(new Vec2(1, 1));
    /** (-1,-1) */
    static readonly NEG_ONE = TypeUtil.readonlyType(new Vec2(-1, -1));
    /** 临时变量 */
    static readonly T = new Vec2();
    /** 临时变量 */
    static readonly T2 = new Vec2();
    /** 临时变量 */
    static readonly T3 = new Vec2();
    /** 临时变量 */
    static readonly T4 = new Vec2();
    /** 临时变量 */
    static readonly T5 = new Vec2();
    /** 内部临时变量 */
    protected static readonly _tpos = new Vec2();

    /** 
     * 复制坐标生成一个新的二维对象
     * @param pos
     */
    static copyPos(pos: Readonly<IVec2>) {
        return new Vec2(pos.x, pos.y);
    }

    /**
     * 重置坐标为零点
     * @param out 
     */
    static resetPos<T extends IVec2>(out: T) {
        out.x = 0;
        out.y = 0;
        return out;
    }

    /**
     * 设置坐标
     * @param out 
     * @param x 
     * @param y 
     */
    static setPos<T extends IVec2>(out: T, x: number, y: number) {
        out.x = x;
        out.y = y;
        return out;
    }

    /**
     * 设置坐标
     * @param out 
     * @param pos
     */
    static setPosTo<T extends IVec2>(out: T, pos: Readonly<IVec2>) {
        out.x = pos.x;
        out.y = pos.y;
        return out;
    }

    /**
     * 增值坐标
     * @param out 
     * @param x 
     * @param y 
     */
    static addPos<T extends IVec2>(out: T, x: number, y: number) {
        out.x += x;
        out.y += y;
        return out;
    }

    /**
     * 增值坐标
     * @param out 
     * @param pos
     */
    static addPosTo<T extends IVec2>(out: T, pos: Readonly<IVec2>) {
        out.x += pos.x;
        out.y += pos.y;
        return out;
    }

    /**
     * 两点之间的距离
     * @param pos1 
     * @param pos2 
     */
    static dis(pos1: Readonly<IVec2>, pos2: Readonly<IVec2>) {
        const x = pos1.x - pos2.x;
        const y = pos1.y - pos2.y;
        return Math.sqrt(x * x + y * y);
    }

    /**
     * 将方向设置为弧度方向
     * @param dir
     * @param rad 
     */
    static setRad<T extends IVec2>(dir: T, rad: number) {
        dir.x = Math.cos(rad);
        dir.y = Math.sin(rad);
        return dir;
    }

    /**
     * 获取方向的弧度
     * @param dir
     */
    static getRad(dir: Readonly<IVec2>) {
        return Math.atan2(dir.y, dir.x);
    }

    /**
     * 位置1朝向位置2的弧度
     * @param pos1 位置1
     * @param pos2 位置2
     */
    static radTo(pos1: Readonly<IVec2>, pos2: Readonly<IVec2>) {
        return Math.atan2(pos2.y - pos1.y, pos2.x - pos1.x);
    }

    /**
     * 位置1朝向位置2的方向
     * @param pos1 位置1
     * @param pos2 位置2
     * @param out 如未设置则返回的是临时变量 请勿保持引用
     */
    static dirTo(pos1: IVec2, pos2: Readonly<IVec2>, out: IVec2 = this._tpos) {
        out.x = pos2.x - pos1.x;
        out.y = pos2.y - pos1.y;
        return this.normalize(out);
    }

    /**
     * 朝目标方向移动dis距离
     * @param pos 当前位置
     * @param target 目标位置
     */
    static move<T extends IVec2>(pos: T, dir: Readonly<IVec2>, dis: number) {
        return this.addPos(pos, dir.x * dis, dir.y * dis);
    }

    /**
     * 朝目标方向移动dis距离
     * @param pos 当前位置
     * @param target 目标位置
     */
    static moveTo<T extends IVec2>(pos: T, target: Readonly<IVec2>, dis: number) {
        const rad = this.radTo(pos, target);
        return this.moveRad(pos, rad, dis);
    }

    /**
     * 朝弧度方向移动dis距离
     * @param pos 当前位置
     * @param rad 弧度方向
     * @param dis 移动距离
     */
    static moveRad<T extends IVec2>(pos: T, rad: number, dis: number) {
        pos.x += Math.cos(rad) * dis;
        pos.y += Math.sin(rad) * dis;
        return pos;
    }

    /**
     * 计算向量的长度（模）
     * @param pos 
     */
    static len(pos: Readonly<IVec2>) {
        return Math.sqrt(this.lenSqr(pos));
    }

    /**
     * 计算向量长度（模）的平方。
     * @param pos 
     */
    static lenSqr(pos: Readonly<IVec2>) {
        return pos.x * pos.x + pos.y * pos.y;
    }

    /**
     * 归一化向量
     * @param pos
     */
    static normalize<T extends IVec2>(pos: T) {
        let len = this.lenSqr(pos);
        if (len > 0) {
            len = 1 / Math.sqrt(len);
            pos.x *= len;
            pos.y *= len;
        }
        return pos;
    }

    /**
     * 坐标线性插值
     * @param pos 
     * @param target 
     * @param t 
     */
    static lerp<T extends IVec2>(pos: T, target: Readonly<IVec2>, t: number) {
        pos.x = MathUtil.lerp(pos.x, target.x, t);
        pos.y = MathUtil.lerp(pos.y, target.y, t);
        return pos;
    }

    /**
     * 一个坐标是否等于另一个坐标
     * @param pos
     * @param target
     */
    static equalsPos(pos: Readonly<IVec2>, target: Readonly<IVec2>) {
        return pos.x === target.x && pos.y === target.y;
    }

    constructor(
        public x = 0,
        public y = 0) { }

    /** 
     * 复制当前坐标生成一个新的二维对象
     */
    copyPos() {
        return new Vec2(this.x, this.y);
    }

    /**
     * 重置坐标为零点
     */
    resetPos() {
        return Vec2.resetPos(this);
    }

    /**
     * 设置坐标
     * @param x 
     * @param y 
     */
    setPos(x = 0, y = 0) {
        return Vec2.setPos(this, x, y);
    }

    /**
     * 设置坐标
     * @param pos
     */
    setPosTo(pos: Readonly<IVec2>) {
        return Vec2.setPosTo(this, pos);
    }

    /**
     * 增值坐标
     * @param out 
     * @param x 
     * @param y 
     */
    addPos(x: number, y: number) {
        return Vec2.addPos(this, x, y);
    }

    /**
     * 增值坐标
     * @param out 
     * @param pos
     */
    addPosTo(pos: Readonly<IVec2>) {
        return Vec2.addPosTo(this, pos);

    }

    /**
     * 距离目标的距离
     * @param pos 
     */
    dis(pos: Readonly<IVec2>) {
        return Vec2.dis(this, pos);
    }

    /**
     * 设置为弧度方向
     * @param rad 
     */
    setRad(rad: number) {
        return Vec2.setRad(this, rad);
    }

    /**
     * 获取当前方向的弧度
     */
    getRad() {
        return Vec2.getRad(this);
    }

    /**
     * 朝向目标的弧度
     * @param pos
     */
    radTo(pos: Readonly<IVec2>) {
        return Vec2.radTo(this, pos);
    }

    /**
     * 朝向目标的方向
     * @param pos
     * @param out 如未设置则返回的是临时变量 请勿保持引用
     */
    dirTo(pos: Readonly<IVec2>, out?: IVec2) {
        return Vec2.dirTo(this, pos, out);
    }

    /**
     * 朝坐标方向移动dis距离
     * @param pos 
     * @param dis 
     */
    move(dir: Readonly<IVec2>, dis: number) {
        return Vec2.move(this, dir, dis);
    }

    /**
     * 朝坐标方向移动dis距离
     * @param pos 
     * @param dis 
     */
    moveTo(pos: Readonly<IVec2>, dis: number) {
        return Vec2.moveTo(this, pos, dis);
    }

    /**
     * 朝弧度方向移动dis距离
     * @param rad 
     * @param dis 
     */
    moveRad(rad: number, dis: number) {
        return Vec2.moveRad(this, rad, dis);
    }

    /**
     * 计算向量的长度（模）
     */
    len() {
        return Vec2.len(this);
    }

    /**
     * 计算向量长度（模）的平方。
     */
    lenSqr() {
        return Vec2.lenSqr(this);
    }

    /**
     * 归一化向量
     */
    normalize() {
        return Vec2.normalize(this);
    }

    /**
     * 线性插值
     * @param target 
     * @param t 
     */
    lerp(pos: Readonly<IVec2>, t: number) {
        return Vec2.lerp(this, pos, t);
    }

    /**
     * 是否等于另一个坐标
     * @param 
     */
    equalsPos(pos: Readonly<IVec2>) {
        return Vec2.equalsPos(this, pos);
    }

}